package com.wpw.dream.concurrent;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * 并发工具类（一）等待多线程完成的CountDownLatch,和join的区别
 * 一个同步辅助类，在完成一组正在其他线程中执行的操作之前，它允许一个或多个线程一直等待。 
	用给定的计数初始化 CountDownLatch。调用countDown()方法，计数减1。在当前计数到达零之前，调用await()方法的线程会一直受阻塞。当前计数到达0之后，会释放所有等待的线程，调用await()的线程的后续调用都将继续执行。这种现象只出现一次,因为CountDownLatch没有提供任何机制去重新设置这个计数值。如果需要重置计数，请考虑使用 CyclicBarrier。 
	CountDownLatch是一个通用同步工具，它有很多用途。将计数 1 初始化的 CountDownLatch 用作一个简单的开/关锁存器，或入口：在通过调用 countDown() 的线程打开入口前，所有调用 await()的线程都一直在入口处等待。用 N初始化的 CountDownLatch 可以使一个线程在 N 个线程完成某项操作之前一直等待，或者使其在某项操作完成 N 次之前一直等待。 
 * 
 * 另外一个带指定时间的await方法，await(long time, TimeUnit unit): 如果计数还没到0，这个方法等待特定时间后，就会不再阻塞当前线程；如果计数到0了，等待时间还没到，当前线程仍然不再阻塞。
 * 
 * 和join的区别：
 * 调用thread.join() 方法必须等thread 执行完毕，当前线程才能继续往下执行，而CountDownLatch通过计数器提供了更灵活的控制，只要检测到计数器为0当前线程就可以往下执行而不用 管相应的thread是否执行完毕。
 * join用于让当前执行线程等待join线程执行结束。其实现原理是不停检查join线程是否存活，如果join线程存活则让当前线程wait，代码片段如下，wait(0)表示永远等待下去。
	while (isAlive()) {
	 wait(0);
	}
	直到join线程中止后，线程的this.notifyAll会被调用，调用notifyAll是在JVM里实现的，所以JDK里看不到，有兴趣的同学可以看看JVM源码。JDK不推荐在线程实例上使用wait，notify和notifyAll方法。
 * 
 * 
 * Project Name：dream-test
 * ClassName：CountDownLatchTest
 * Description：
 * @author: wupengwei
 * @date: 2017年5月24日 上午11:06:17
 * note:
 *
 */
public class CountDownLatchTest {
	
	public static void main(String[] args) throws InterruptedException {
		
		final CountDownLatch cl = new CountDownLatch(2);
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				cl.countDown();
				System.out.println("线程1唤醒");
			}
		}).start();
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				try {
					Thread.sleep(1000);
					cl.countDown();
					System.out.println("线程2唤醒");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				try {
					System.out.println("次线程等待被唤醒");
					cl.await();
					System.out.println("次线程继续执行");
					
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start();
		
		System.out.println("主线程要等待被唤醒");
//		cl.await(400,TimeUnit.SECONDS);
		cl.await();
		System.out.println("主线程继续执行");
	}

}
